package com.edu.robot.modules.robot.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.edu.robot.core.enums.IntentEnum;
import com.edu.robot.core.utils.HttpClientUtil;
import com.edu.robot.model.R;
import com.edu.robot.model.enums.ResultCodeEnum;
import com.edu.robot.model.error.BizException;
import com.edu.robot.modules.robot.controller.vo.PageQuery;
import com.edu.robot.modules.robot.controller.vo.ToolVO;
import com.edu.robot.modules.robot.corvert.ToolCovert;
import com.edu.robot.modules.robot.dto.*;
import com.edu.robot.modules.robot.mapper.CrToolMapper;
import com.edu.robot.modules.robot.model.CrTool;
import com.edu.robot.modules.robot.service.CrToolService;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author 86177
 * @description 针对表【cr_tool】的数据库操作Service实现
 * @createDate 2025-02-22 14:34:38
 */
@Service
@Slf4j
public class CrToolServiceImpl extends ServiceImpl<CrToolMapper, CrTool>
		implements CrToolService {

	@Override
	public R<?> addTool(ToolVO toolVO) {
		log.info("CrToolServiceImpl addTool toolVO:{}", toolVO);

		if(Objects.isNull(toolVO)){
			throw new BizException(ResultCodeEnum.PARAM_INVALID);
		}

		CrTool convert = ToolCovert.convert(toolVO);

		save(convert);

		return R.success(Boolean.TRUE);
	}

	/**
	* @Description:
	* {工具名称}：{功能描述}
	 * 			参数规范：
	 * 			- 参数1：类型/取值范围/必填
	 * 			- 参数2：类型/取值范围/必填
	*/

	/**
	 * @Description: 获取工具调用模板
	 * 根据工具ID集合生成结构化调用模板说明，包含：
	 * - 工具名称和功能描述
	 * - 参数规范（名称、类型、是否必填）
	 */
	@Override
	public R<String> getFunctionCallTemplate(List<String> toolIds) {
		// 1. 参数校验
		if (CollectionUtil.isEmpty(toolIds)) {
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "工具ID列表不能为空");
		}

		// 2. 查询有效工具列表
		List<CrTool> tools = list(new LambdaQueryWrapper<CrTool>()
				.in(CrTool::getId, toolIds)
				.eq(CrTool::getDeleted, 0)
				.eq(CrTool::getStatus, 1)
				.orderByAsc(CrTool::getCreatedAt));

		if (CollectionUtil.isEmpty(tools)) {
			throw new BizException(ResultCodeEnum.DATA_NOT_FOUND, "未找到可用工具");
		}

		// 3. 生成模板内容
		String templateContent = tools.stream()
				.map(this::buildToolTemplate)
				.collect(Collectors.joining("\n\n"));
		R<String> success = R.success();
		success.setData(String.format(IntentEnum.INTENT_TOOL.getSysPrompt(), templateContent));
		return success;
	}

	/**
	 * 构建单个工具模板
	 */
	private String buildToolTemplate(CrTool tool) {
		// 1. 基础信息
		String toolName = tool.getName();
		String toolDesc = tool.getDescription();

		// 2. 解析参数配置
		List<ParameterDTO> parameters = parseToolConfig(tool);

		// 3. 构建参数规范
		String paramsContent = parameters.stream()
				.map(p -> String.format("""
								- %s:
									类型: %s
									取值范围: %s
									是否必填: %s
									参数描述: %s
								""",
						p.getName(),
						p.getType(),
						p.getRange(),
						p.isRequired() ? "true" : "false",
						p.getDescription()
				))
				.collect(Collectors.joining("\n"));

		// 4. 生成模板
		return String.format(
				"""
				工具名称: %s
				功能描述: %s
				参数规范:
				%s
				""",
				toolName, toolDesc,
				paramsContent.isEmpty() ? "  无参数要求" : paramsContent);
	}

	/**
	 * 解析工具配置
	 */
	private List<ParameterDTO> parseToolConfig(CrTool tool) {
		try {
			ToolConfigDTO config = JSONUtil.toBean(
					tool.getConfigTemplate(),
					ToolConfigDTO.class);
			return config.getParameters();
		} catch (Exception e) {
			throw new BizException(ResultCodeEnum.CONFIG_ERROR, "工具配置解析失败: " + tool.getName());
		}
	}

	@Override
	public String useTool(String toolId, Map<String, Object> params) {
		// 1. 查询工具配置
		CrTool tool = getById(toolId);
		if (tool == null) {
			throw new BizException(ResultCodeEnum.INTERNAL_ERROR, "工具不存在");
		}

		// 2. 获取并验证配置模板
		String configTemplate = tool.getConfigTemplate();
		if (StringUtils.isBlank(configTemplate)) {
			throw new BizException(ResultCodeEnum.CONFIG_ERROR, "工具参数未配置");
		}

		// 3. 解析工具配置
		ToolConfigDTO config;
		try {
			config = JSONUtil.toBean(configTemplate, ToolConfigDTO.class);
		} catch (Exception e) {
			throw new BizException(ResultCodeEnum.CONFIG_ERROR, "工具配置解析失败");
		}

		// 4. 参数校验
		List<String> requiredParams = config.getParameters().stream()
				.filter(ParameterDTO::isRequired)
				.map(ParameterDTO::getName)
				.toList();
		if (!params.keySet().containsAll(requiredParams)) {
			throw new BizException(ResultCodeEnum.PARAM_INVALID,
					"缺少必填参数: " + requiredParams.stream()
							.filter(p -> !params.containsKey(p))
							.collect(Collectors.joining(", ")));
		}

		//4.没有的,赋值默认值
		for (ParameterDTO parameter : config.getParameters()) {
			if (params.containsKey(parameter.getName())) {
				continue;
			}
			params.put(parameter.getName(), parameter.getDefaultValue());
		}

		// 5. 执行HTTP请求
		String responseBody;
		try {
			if (Method.GET.name().equalsIgnoreCase(config.getMethod())) {
				responseBody = HttpClientUtil.get(config.getUrl(), params, config.getHeaders());
			} else {
				responseBody = HttpClientUtil.post(config.getUrl(), params, config.getHeaders());
			}
		} catch (Exception e) {
			log.error("工具调用失败", e);
			throw new BizException(ResultCodeEnum.THIRD_PARTY_ERROR, "工具调用失败"+e.getMessage());
		}

		if (StringUtils.isBlank(responseBody)) {
			throw new BizException(ResultCodeEnum.INTERNAL_ERROR, "工具返回空响应");
		}

		// 6. 解析响应结果
		try {
			JsonNode root = new ObjectMapper().readTree(responseBody);
			ToolResponse responseConfig = config.getResponse();

			// 尝试解析成功路径
			String successValue = parseJsonPath(root, responseConfig.getSuccessPath());
			if (successValue != null) {
				return successValue;
			}

			// 尝试解析错误路径
			String errorValue = parseJsonPath(root, responseConfig.getErrorPath());
			if (errorValue != null) {
				return successValue;
			}

			throw new BizException(ResultCodeEnum.INTERNAL_ERROR, "无法解析响应内容");
		} catch (IOException e) {
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "响应解析失败"+e.getMessage());
		}
	}

	@Override
	public R<List<ToolInfoDTO>> getToolList(List<String> toolIdList) {
		// 1. 参数校验
		if (CollectionUtil.isEmpty(toolIdList)) {
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "工具ID列表不能为空");
		}

		// 2. 查询有效工具列表
		List<CrTool> tools = list(new LambdaQueryWrapper<CrTool>()
				.in(CrTool::getId, toolIdList)
				.eq(CrTool::getDeleted, 0)
				.eq(CrTool::getStatus, 1)
				.orderByAsc(CrTool::getCreatedAt));

		if (CollectionUtil.isEmpty(tools)) {
			throw new BizException(ResultCodeEnum.DATA_NOT_FOUND, "未找到可用工具");
		}

		return R.success(tools.stream().map(ToolCovert::covert).toList());

	}

	@Override
	public PageResult<ToolInfoDTO> listTool(PageQuery<ToolVO> pageQuery) {

		if (pageQuery == null){
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "pageQuery is null");
		}

		//获取分页大小与当前页，默认1
		Long size = Optional.ofNullable(pageQuery.getPageSize()).orElse(10L);
		Long current = Optional.ofNullable(pageQuery.getPageNum()).orElse(1L);

		LambdaQueryWrapper<CrTool> queryWrapper = new LambdaQueryWrapper<>();

		ToolVO query = pageQuery.getQuery();

		if (query != null){
			Optional.ofNullable(query.getId()).ifPresent(id -> queryWrapper.eq(CrTool::getId, id));
			Optional.ofNullable(query.getName()).ifPresent(name -> queryWrapper.like(CrTool::getName, name));
		}

		Page<CrTool> page = page(new Page<>(current, size), queryWrapper);

		if (page == null){
			return null;
		}

		PageResult<ToolInfoDTO> pageResult = new PageResult<>();

		pageResult.setTotal(page.getTotal());
		pageResult.setCurrentPage(page.getCurrent());
		pageResult.setTotalPages(page.getPages());
		pageResult.setRecords(
				page.getRecords().stream().map(ToolCovert::covert).collect(Collectors.toList()));


		return pageResult;
	}

	@Override
	public R<?> deleteTool(String toolId) {
		if (StringUtils.isBlank(toolId)){
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "toolId is blank");
		}
		if (removeById(toolId)){
			return R.success(Boolean.TRUE);
		}
		return R.fail(ResultCodeEnum.FAIL);
	}

	@Override
	public R<?> editTool(ToolVO toolVO) {

		if (toolVO == null){
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "toolVO is null");
		}

		if (StringUtils.isBlank(toolVO.getId())){
			throw new BizException(ResultCodeEnum.PARAM_INVALID, "toolId is blank");
		}
		CrTool convert = ToolCovert.convert(toolVO);
		if (updateById(convert)){
			return R.success(Boolean.TRUE);
		}

		return null;
	}

	/**
	 * 使用JSON Pointer解析JSON路径
	 */
	private static String parseJsonPath(JsonNode root, String path) {
		if (StringUtils.isBlank(path)) return null;

		try {
			// 将配置的路径转换为JSON Pointer格式
			String pointerPath = path.startsWith("/") ? path : "/" + path.replace(".", "/");
			JsonNode node = root.at(JsonPointer.compile(pointerPath));

			if (node.isMissingNode()) return null;
			if (node.isTextual()) return node.asText();
			return node.toString();
		} catch (IllegalArgumentException e) {
			throw new BizException(ResultCodeEnum.CONFIG_ERROR, "无效的JSON路径配置: " + path);
		}
	}


	public static void main(String[] args) throws JsonProcessingException {
		// 测试用JSON数据
		final String testJson = """
        {
            "user": {
                "name": "John",
                "age": 30,
                "contacts": [
                    {"type": "email", "value": "john@example.com"},
                    {"type": "phone", "value": "123-4567"}
                ],
                "metadata": {
                    "createdAt": "2023-01-01"
                }
            },
            "system": {
                "status": "OK",
                "error": {
                    "code": 500,
                    "message": "Internal Error"
                }
            }
        }
        """;
		JsonNode root = new ObjectMapper().readTree(testJson);

		System.out.println(parseJsonPath(root, "user.name")); // 输出: John
	}

}




